﻿using SettlersAuto.Data.Entities;
using SettlersAuto.Web.Models;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.UI.DataVisualization.Charting;

namespace SettlersAuto.Web.Controllers
{
    public partial class TradeController : Controller
    {

        private const string CoinProductName = "Coin";
        private static readonly string[] Currencies = new[] { "Coin", "HalloweenResource", "Marble" };

        //
        // GET: /Trade/

        public virtual ActionResult Index(string currencyName = CoinProductName)
        {
            using (var db = new SettlersAutoDb())
            {
                var latestSession = db.TradeSessions.OrderByDescending(s => s.TradeSessionId).FirstOrDefault();
                if (latestSession == null)
                {
                    return View();
                }

                var productPrices =
                    (from slot in db.TradeSlots.FromSession(latestSession.TradeSessionId)
                     where slot.DemandProductName == currencyName
                     group slot by slot.OfferProductName into grp
                     let name = grp.Key
                     let minPrice = grp.Min(s => s.Price())
                     select new ProductSummaryModel
                     {
                         ProductName = name,
                         ProductDisplayName = name,
                         BestPrice = minPrice
                     }).ToList();

                foreach (var p in productPrices)
                {
                    p.AveragePrice = db.TradeSlots
                        .WithProducts(p.ProductName, currencyName)
                        .WithTime(DateTime.Now)
                        .GetAveragePrice();
                }

                var productsByCategory =
                    from p in productPrices
                    group p by GetProductCategory(p.ProductName) into grp
                    select new CategoryModel<ProductSummaryModel>
                    {
                        CategoryName = grp.Key,
                        Products = grp.ToList()
                    };

                var result = new TradeOverviewModel
                {
                    LatestTradeSession = latestSession,
                    BestOffersCategories = productsByCategory.OrderBy(c => c.CategoryName).ToList(),
                    Currencies = Currencies.Where(c => c != currencyName).ToList(),
                    CurrentCurrency = currencyName
                };

                return View(result);
            }
        }

        public virtual ActionResult IsNewSessionAvailable(int currentSessionId)
        {
            using (var db = new SettlersAutoDb())
            {
                var latestSession = db.TradeSessions.Max(s => s.TradeSessionId);

                var result = new
                {
                    dataAvailable = latestSession > currentSessionId
                };

                return Json(result, JsonRequestBehavior.AllowGet);
            }
        }

        public virtual ActionResult ProductDetails(string productName, string currencyName = CoinProductName)
        {
            var model = new ProductDetailsModel 
            { 
                ProductName = productName,
                CurrentCurrency = currencyName
            };

            using (var db = new SettlersAutoDb())
            {
                var latestSession = db.TradeSessions.Max(s => s.TradeSessionId);
                var offers = db.TradeSlots
                    .WithProducts(productName, currencyName)
                    .FromSession(latestSession);

                var demand = db.TradeSlots
                    .WithProducts(currencyName, productName)
                    .FromSession(latestSession);
                    

                model.Demand = demand.OrderBy(ts => ts.Price()).ToList().Select(ts => ts.Invert());
                model.Offers = offers.OrderBy(ts => ts.Price()).ToList();
                model.AveragePrice = db.TradeSlots
                    .WithProducts(productName, currencyName)
                    .WithTime(DateTime.Now)
                    .GetAveragePrice();

                return View(model);
            }
        }

        public virtual ActionResult GoodBargain()
        {
            using (var db = new SettlersAutoDb())
            {
                var latestSession = db.TradeSessions.Max(s => s.TradeSessionId);

                var tradeSlots = db.TradeSlots.FromSession(latestSession).ToList();

                var byDemandProduct = tradeSlots.ToLookup(ts => ts.DemandProductName);

                var bargains =
                    from offer1 in tradeSlots
                    from offer2 in byDemandProduct[offer1.OfferProductName]
                    where offer1.DemandProductName == offer2.OfferProductName
                    let gain1 = new SlotProduct(offer1.OfferProductName, offer1.OfferQuantity - offer2.DemandQuantity)
                    where gain1.Quantity >= 0
                    let gain2 = new SlotProduct(offer2.OfferProductName, offer2.OfferQuantity - offer1.DemandQuantity)
                    where gain2.Quantity >= 0
                    select new BargainModel
                    {
                        Slot1 = offer1,
                        Slot2 = offer2,
                        Gain1 = gain1,
                        Gain2 = gain2
                    };

                var x = bargains.ToList();

                return View();
            }
        }

        public virtual ActionResult PriceHistoryImg(string productName, bool offerPrices = true, string currencyName = CoinProductName)
        {
            using (var db = new SettlersAutoDb())
            {
                var now = DateTime.Now;
                var dates = Enumerable.Range(0, 30).Select(i => now.AddDays(-i)).Reverse();

                var points =
                    (from date in dates
                     let slots = db.TradeSlots.WithTime(date)
                     let offerPrice = slots.WithProducts(productName, currencyName).GetAveragePrice()
                     let demandPrice = slots.WithProducts(currencyName, productName).GetAveragePrice()
                     select new
                     {
                         Date = date,
                         OfferPrice = offerPrice,
                         DemandPrice = demandPrice
                     }).ToList();

                var chart = new Chart
                {
                    Width = 600,
                    Height = 300
                };

                var gridColor =Color.FromArgb(200, 200, 200);
                var lightGridColor = Color.FromArgb(230, 230, 230);

                var area = new ChartArea();
                area.AxisY.MajorGrid.LineColor = gridColor;
                area.AxisX.MajorGrid.LineColor = gridColor;
                area.AxisY.MinorGrid.Enabled = true;;
                area.AxisY.MinorGrid.LineColor = lightGridColor;
                area.AxisX.MinorGrid.Enabled = true;
                area.AxisX.MinorGrid.LineColor = lightGridColor;
                chart.ChartAreas.Add(area);

                // create and customize your data series.
                var seriesOffer = CreateSeries();
                var seriesDemand = CreateSeries();

                foreach (var point in points)
                {
                    seriesOffer.Points.AddXY(point.Date.ToShortDateString(), point.OfferPrice);
                    seriesDemand.Points.AddXY(point.Date.ToShortDateString(), 1m / point.DemandPrice);
                }

                seriesOffer.Color = Color.Green;
                seriesOffer.BorderWidth = 2;
                seriesDemand.Color = Color.Blue;

                chart.Series.Add(seriesOffer);
                chart.Series.Add(seriesDemand);

                var returnStream = new MemoryStream();
                chart.ImageType = ChartImageType.Png;
                chart.SaveImage(returnStream);
                returnStream.Position = 0;

                return new FileStreamResult(returnStream, "image/png");
            }
        }

        private static Series CreateSeries()
        {
            var series = new Series();
            series.Font = new Font("Segoe UI", 8.0f, FontStyle.Bold);
            series.ChartType = SeriesChartType.Line;
            return series;
        }

        private string GetProductCategory(string productName)
        {
            if(productName.StartsWith("Adventure"))
            {
                return "Adventure";
            }

            if(productName.StartsWith("BuildBuilding"))
            {
                return "Building";
            }

            if (productName.StartsWith("FillDeposit"))
            {
                return "Fill Deposit";
            }

            if (productName.StartsWith("ProductivityBuff") ||
                productName.StartsWith("EventBuff") ||
                productName.StartsWith("SpeedUpPopulationGrowth") ||
                productName.StartsWith("HalloweenEvent") ||
                productName.StartsWith("RecruitingBuff")
                )
            {
                return "Buff";
            }

            return string.Empty;
        }
    }
}
